#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import pprint
import StringIO
import traceback
import struct
import base64
import sqlite3
from optparse import OptionParser
import time

from utils import _exec_shell1, _exec_remote1, _str2dict, _derror, _dwarn, mutil_exec

DB_HASH = 10


class Key(object):
    def __init__(self, key):
        self.key = key
        self.chkid = self._parse_key(key)
        self.chkid_struct = self._db_key(self.chkid)

    @staticmethod
    def _map_chunk_type(t):
        mapping = {
            'pool':    1,
            'subpool': 2,
            'vol':     3,
            'subvol':  4,
            'raw':     5,
        }
        return mapping[t]

    def _parse_key(self, key):
        l = key.split('.')
        return int(l[1]), self._map_chunk_type(l[0]), int(l[2])

    def _db_key(self, chkid):
        return struct.pack('QII', chkid[0], chkid[1], chkid[2])

    def __str__(self):
        return '<%s, %s, %s>' % (self.key, self.chkid, self.chkid_struct)

    def is_raw(self):
        return self.chkid[1] == 5


class Sqlite(object):
    def __init__(self):
        self.db_home = '/opt/fusionstack/data/chunk'

        #self.conns = [self.connect(i) for i in range(DB_HASH)]
        #for x in self.conns:
        #    x.row_factory = sqlite3.Row

    def connect(self, idx):
        return sqlite3.connect('%s/%d.db' % (self.db_home, idx))

    @staticmethod
    def _parse_db_record(item):
        return {
            'chkid': struct.unpack('QII', base64.b64decode(item['key'])),
            'disk': item['disk'],
            'offset': item['offset'],
            'pool': item['pool'],
            'parent': struct.unpack('QII', base64.b64decode(item['parent'])),
            'meta_version': item['meta_version'],
            'fingerprint': item['fingerprint'],
            'priority': item['priority'],
        }

    def _find(self, i, key=None):
        with self.connect(i) as conn:
            ko = Key(key)
            key2 = base64.b64encode(ko.chkid_struct)

            if ko.is_raw():
                sql = "select * from raw where key='%s'" % key2
            else:
                sql = "select * from metadata where key='%s'" % key2

            cursor = conn.cursor()
            cursor.execute(sql)
            items = cursor.fetchall()

            return [self._parse_db_record(item) for item in items]

    def find(self, key=None):
        l = []
        for i in range(DB_HASH):
            x = self._find(key)
            if x:
                l.append((i, x))
        return l

    def _pool_list(self, i, tables, pool=None):
        with self.connect(i) as conn:
            cursor = conn.cursor()
            for tbl in tables:
                if pool:
                    sql = "select * from %s where pool='%s'" % (tbl, pool)
                else:
                    sql = "select * from %s" % (tbl)

                _dwarn('%4d sql %s' % (i, sql))

                cursor.execute(sql)

                for j, x in enumerate(cursor.fetchall()):
                    print '%4d %8d %s' % (i, j, self._parse_db_record(x))

    def pool_list(self, tables=['raw', 'metadata'], pool=None):
        for i in range(DB_HASH):
            self._pool_list(i, tables, pool)

    def _pool_del(self, i, tables, pool):
        with self.connect(i) as conn:
            cursor = conn.cursor()
            for tbl in tables:
                start = time.time()

                sql = "select count(*) from %s where pool='%s'" % (tbl, pool)
                cursor.execute(sql)
                count = cursor.fetchone()[0]

                sql = "delete from %s where pool='%s'" % (tbl, pool)
                _dwarn('%4d sql %s count %d' % (i, sql, count))

                cursor.execute(sql)
                conn.commit()

                end = time.time()
                _derror('%4d sql %s count %d used %d seconds' % (i, sql, count, end - start))

    def pool_del(self, tables=['raw', 'metadata'], pool=None):
        args = [[i, tables, pool] for i in range(DB_HASH)]
        mutil_exec(self._pool_del, args)

    def _summary(self, i, data):
        with self.connect(i) as conn:
            cursor = conn.cursor()
            conn_data = {}
            for tbl in ['raw', 'metadata']:
                sql = "select count(*) from %s" % (tbl)
                cursor.execute(sql)
                conn_data[tbl] = cursor.fetchone()[0]

            data[i] = conn_data

    def summary(self):
        data = {}
        for i in range(DB_HASH):
            self._summary(i, data)

        pprint.pprint(data)


def main():
    sql = Sqlite()
    sql.summary()
    # sql.pool_list()
    # sql.pool_list(tables=['metadata'])
    # sql.pool_list(tables=['raw'])
    # sql.pool_list(pool='ssd-pool')
    # sql.pool_del(pool='ssd-pool')


if __name__ == '__main__':
    main()
